// version = 0.0.1
'use strict';

/*
    目标：扫码进行任意p2p连接
*/

// 通用节点类，负责进行连接
class Node {
    constructor(name = '_', exchange_methods = {}){
        this._make_id(name);

        this.exchange_methods = Object.assign(_default_exchange_methods,exchange_methods);
        this.exchange_methods.init(this);

        this.waiting_offer_pc = this._make_pc(proactive = true);
        this.waiting_answer_pc = this._make_pc(proactive = false);

        this.connected_PCs = {
        }
    }

    _make_id(name){
        // 生成随机id
        this.id = name + Math.random().toString(36);
    }

    _make_pc(proactive = true){
        const config = {
            iceServers: [{ urls: "stun:stun.ideasip.com" }]
        }
        const pc = new RTCPeerConnection(config);
        pc.temp_candidates = [];
        pc.candidates = [];

        if (proactive){
            pc.onnegotiationneeded = async (e) => {
                const offer = await e.target.createOffer()
                await e.target.setLocalDescription(offer);
                /*
                    此处更新key
                */
               log("key 更新点(offer_obj.pc.createOffer)");
               this.exchange_methods.send_key(this);
            };

            pc.addEventListener('connectionstatechange',(e) => {
                switch (e.target.connectionState) {
                    case 'connected':
                        this.connected_PCs[e.target.remote_id] = e.target;
                        this.waiting_offer_pc = this._make_pc(proactive = true);
                        break;
                }
            });
        } else {

            pc.addEventListener('connectionstatechange',(e) => {
                switch (e.target.connectionState) {
                    case 'connected':
                        this.connected_PCs[e.target.remote_id] = e.target;
                        this.waiting_answer_pc = this._make_pc(proactive = false);
                        break;
                }
            });
        }


        pc.onicecandidate = ({ candidate }) => {
            if (candidate) {
                e.target.temp_candidates.push(candidate)
            } else {
                e.target.candidates = this.offer_obj.temp_candidates;
                e.target.temp_candidates = [];
                /*
                    此处更新key
                */
               log("key 更新点(offer_obj.pc.onicecandidate)");
               this.exchange_methods.send_key(this);
            }
        }

        pc.addEventListener('connectionstatechange',(e) => {
            switch (e.target.connectionState) {
                case "connecting":
                    break;
                case 'connected':
                    this.exchange_methods.connected(this);
                    break;
                default:
                    log("收到未知状态:(" + e.target.connectionState + ")")
            }
        });

        return pc;
    }

    _show_info(){
        html = 
        ``
        
    }

    async _recive_key(input_key) {

        if (input_key.id in this.connected_PCs){
            log(`该远程节点(ID:${input_key.id})已经连接!`);
        } else {
            switch(input_key.desc.type){
                case "offer":
                    await this.waiting_answer_pc.setRemoteDescription(input_key.desc);
                    const answer = await this.waiting_answer_pc.createAnswer()
                    await this.waiting_answer_pc.setLocalDescription(answer);
                    log(`(${this.id})[waiting_answer_pc]offer description已处理，answer description已生成，请回复`);
                    /*
                        此处更新key
                    */
                    log("key 更新点(waiting_answer_pc.createAnswer)");
                    this.exchange_methods.send_key(this);

                    for (const i in input_key.candis) {

                        if (input_key.candis[i]) {
                            await this.waiting_answer_pc.addIceCandidate(input_key.candis[i]);
                        };
                    };
                    log(`${this.id}[waiting_answer_pc]远程candidates已加入`);
                    break;
                case "answer":
                    await this.waiting_offer_pc.setRemoteDescription(input_key.desc);
                    log(`(${this.id})[waiting_offer_pc]answer description已处理`);

                    for (const i in input_key.candis) {

                        if (input_key.candis[i]) {
                            await this.waiting_offer_pc.addIceCandidate(input_key.candis[i]);
                        };
                    };
                    log(`${this.id}[waiting_offer_pc]远程candidates已加入`);
                    break;
            }
        }




    }

    _default_exchange_methods = {
        'make_key':(self) => {
            let combined_key;
            if (self.waiting_answer_pc.localDescription !== null && self.waiting_answer_pc.candidates.length){
                combined_key = {
                    'desc':self.waiting_answer_pc.localDescription,
                    'candi':self.waiting_answer_pc.candidates
                }
            } else if (self.waiting_offer_pc.localDescription !== null && self.waiting_offer_pc.candidates.length){
                combined_key = {
                    'desc':self.waiting_offer_pc.localDescription,
                    'candi':self.waiting_offer_pc.candidates
                }
            } else {
                log("节点没有准备好，无法生成key");
            }
            return combined_key;
        },
    }

    _text_exchange_methods = {
        'init': (self) => {
            append_html(`
            <div id="${this.id}_text_exchange_div" style="max-width: 500px; background-color:#CC6699">

                <p>${this.id}的信息:</p>
                <p id="${this.id}_self_text_str" style="background-color:#00FFFF">等待自身信息生成</p>

                <p>${this.id}传入信息输入区:</p>
                <textarea id="${this.id}_input_text_textarea"></textarea>
                <button id="${this.id}_confirm_input_text_btn" disabled>确认传入</button>

            </div>`);

            // 设置UI
            $(`#${this.id}_confirm_input_text_btn`).click(c_i_text);

            $(`#${this.id}_input_text_textarea`).change(() => { $(`#${this.id}_confirm_input_text_btn`).attr("disabled", false); });

            let c_i_text = async() => {
                const input_key = JSON.parse($(`#${this.id}_input_text_textarea`).val());
                await this._recive_key(input_key);
            };
        },

        'send_key':(self) => {
            let combined_key = self.exchange_methods.make_key(self);
            if (combined_key !== null) $(`#${this.id}_self_text_str`).text(JSON.stringify(combined_key));
        },
        'onconnected':(self) => {
            self.exchange_methods.send_key(self);
            // $(`#${this.id}_self_text_str`).text("连接成功!")
            // $(`#${this.id}_confirm_input_text_btn`).attr("disabled", true);
            // $(`#${this.id}_input_text_textarea`).attr("disabled", true);
        }
    }

    close(){
        for (let i in this.connected_PCs){
            this.connected_PCs[i].close();
            this.connected_PCs[i] = null;
        }
        this.connected_PCs = null;
    }
}


class Data_Node extends Node{
    constructor(node_id = null,exchange_methods = 'text'){
        super(node_id,exchange_methods);
        this.offer_obj.channel = this.offer_obj.pc.createDataChannel("Channel");
        this.offer_obj.channel.onopen = (e) => {
            this.channel = this.offer_obj.channel;
            this.channel.onMessage = (e) => {this.onMessage(e);}
            this.channel.onclose = (e) => {this.onclose(e);}
            this.onopen(e);
        }
        this.answer_obj.pc.ondatachannel = (event) => {
            this.answer_obj.channel = event.channel;
            this.answer_obj.channel.onopen = (e) => {
                this.channel = this.answer_obj.channel;
                this.channel.onMessage = (e) => {this.onMessage(e);}
                this.channel.onclose = (e) => {this.onclose(e);}
                this.onopen(e);
            }

        }
    }
    sendData(data){
        if(this.channel){
            this.channel.send(data);
        }
    }
    onMessage = (e) => {};
    onopen = (e) => {};
    onclose = (e) => {};

    close(){
        this.offer_obj.channel.close();
        this.answer_obj.channel.close();
        super.close();
    }

}

function append_html(html) {
    $("body").append(html);
};